package com.ljs.module.controller;

import com.ljs.module.common.DataBean;
import com.ljs.module.entity.smartbi.ExtensionsList;
import com.ljs.module.entity.smartbi.ExtensionsListSearchDto;
import com.ljs.module.util.ExtensionListUtil;
import com.ljs.module.util.Util;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * extension.list 管理控制器
 * Created by lijunsai on 2021/07/22
 */
@Controller
@RequestMapping("/extension")
public class SmartbiController {

    @ResponseBody
    @GetMapping("showExtensionList")
    public List<List<ExtensionsList>> showExtensionList(String title) throws IOException {
        if (StringUtils.isBlank(title)) {
            return new ArrayList<>();
        }
        List<ExtensionsList> extensionsLists = ExtensionListUtil.getExtensionsList(title);
        List<List<ExtensionsList>> ret = new ArrayList<>();
        ret.add(ExtensionListUtil.getNoExt(extensionsLists));
        ret.add(ExtensionListUtil.getHistoryExtensionsList(title));
        ret.add(ExtensionListUtil.loadExtFileList(ExtensionListUtil.listPath.get(title) + Util.replaceFileSeparor("/WEB-INF/extensions/"), extensionsLists));
        return ret;
    }

    @ResponseBody
    @GetMapping("addTitle")
    public String addTitle(String title, String path) {
        if (StringUtils.isBlank(title) || StringUtils.isBlank(path)) {
            return "不能为空";
        }
        File file = new File(path);
        if (!file.exists()) {
            return "文件不存在";
        }
        if (!ExtensionListUtil.addListPath(title, path)) {
            return "该值已存在";
        }
        return "添加成功";
    }

    @ResponseBody
    @GetMapping("modifyTitle")
    public String modifyTitle(String oldTitle, String title, String path) {
        if (StringUtils.isBlank(title) || StringUtils.isBlank(path)) {
            return "不能为空";
        }
        // 先删后加
        ExtensionListUtil.deleteListPath(oldTitle);
        ExtensionListUtil.addListPath(title, path);
        return "添加成功";
    }

    @ResponseBody
    @GetMapping("deleteTitle")
    public String deleteTitle(String title) {
        if (StringUtils.isBlank(title)) {
            return "删除失败";
        }
        ExtensionListUtil.deleteListPath(title);
        ExtensionListUtil.changeListPathConfig();
        return "删除成功";
    }

    @ResponseBody
    @GetMapping("getTitles")
    public Map<String, String> getTitles(){
        return ExtensionListUtil.listPath;
    }

    @ResponseBody
    @PostMapping("update")
    public boolean update(String[] list, String[] history, String title) throws IOException {
        List<ExtensionsList> extensionsList = ExtensionListUtil.getExtensionsList(title);
        extensionsList = ExtensionListUtil.getExt(extensionsList);
        if (list != null || list.length != 0) {
            extensionsList.addAll(ExtensionListUtil.splitToExtensionList(list));
        }
        List<ExtensionsList> historyExtensionsList = ExtensionListUtil.getHistoryExtensionsList(title);
        if (history == null || history.length == 0) {
            historyExtensionsList.clear();
        } else {
            historyExtensionsList = ExtensionListUtil.splitToExtensionList(history);
        }
        ExtensionListUtil.change(extensionsList, historyExtensionsList, title);
        return true;
    }

    @ResponseBody
    @GetMapping("getGlobalHistory")
    public List<ExtensionsList> getGlobalHistory(){
        return ExtensionListUtil.globalHistoryExtensionsLists;
    }

    @ResponseBody
    @PostMapping("updateGlobalHistory")
    public String updateGlobalHistory(@RequestBody List<ExtensionsList> list){
        ExtensionListUtil.globalHistoryExtensionsLists = list;
        ExtensionListUtil.changeGlobalHistory();
        return "更新成功";
    }

    @ResponseBody
    @PostMapping("searchGlobalHistory")
    public List<ExtensionsListSearchDto> searchGlobalHistory(String search){
        if (StringUtils.isBlank(search)) {
            return getGlobalHistory().stream().map(x -> x.transDto()).collect(Collectors.toList());
        }
        String[] searchSplit = search.toLowerCase().split(" ");
        List<ExtensionsListSearchDto> sortedSet = new ArrayList<>();
        for (ExtensionsList globalHistoryExtensionsList : ExtensionListUtil.globalHistoryExtensionsLists) {
            try {
                Map<Integer, String> lightIndex = new HashMap<>();
                ExtensionsListSearchDto dto = globalHistoryExtensionsList.transDto();
                for (String s : searchSplit) {
                    Pattern p = Pattern.compile(s, Pattern.CASE_INSENSITIVE);
                    Matcher m = p.matcher(dto.getShortName());
                    while(m.find()){
                        BigDecimal bigDecimal = new BigDecimal(dto.getShortName().length());
                        BigDecimal bigDecimal1 = new BigDecimal(s.length());
                        BigDecimal divide = bigDecimal1.divide(bigDecimal, 2, BigDecimal.ROUND_HALF_UP);
                        if (dto.getScore() != null) {
                            dto.setScore(divide.add(new BigDecimal(dto.getScore()), new MathContext(2)).doubleValue());
                        } else {
                            dto.setScore(divide.doubleValue());
                        }
                        int start = m.start();
                        int end = m.end();
                        String s1 = lightIndex.get(start);
                        if (StringUtils.isBlank(s1)) {
                            lightIndex.put(start, "{");
                        } else {
                            lightIndex.put(start, s1 + "{");
                        }
                        String s2 = lightIndex.get(end);
                        if (StringUtils.isBlank(s2)) {
                            lightIndex.put(end, "}");
                        } else {
                            lightIndex.put(end, s2 + "}");
                        }
                    }
                }

                if (dto.getScore() != null) {
                    sortedSet.add(dto);
                    String lightName = "";
                    String[] split = dto.getShortName().split("");
                    for (int i = 0; i < split.length; i++) {
                        if (!StringUtils.isBlank(lightIndex.get(i))) {
                            lightName += lightIndex.get(i).replaceAll("\\{","<span style='color:red'>").replaceAll("\\}", "</span>");
                        }
                        lightName += split[i];
                    }
                    if (!StringUtils.isBlank(lightIndex.get(dto.getShortName().length()))){
                        lightName += lightIndex.get(dto.getShortName().length()).replaceAll("\\{","<span style='color:red'>").replaceAll("\\}", "</span>");
                    }
                    dto.setLightWord(lightName);
                }
            } catch (Exception e) {

            }
        }
        return sortedSet.stream().sorted(Comparator.comparing(ExtensionsListSearchDto::getScore).reversed()).collect(Collectors.toList());
    }

    @ResponseBody
    @PostMapping("/loadExtensions")
    public DataBean<List<ExtensionsList>> loadExtensions(String path, String type) {
        ExtensionListUtil.searchExensions(path, type.equals("append"));
        return DataBean.success().setData(ExtensionListUtil.globalHistoryExtensionsLists);
    }

    @ResponseBody
    @GetMapping("/del/extFile")
    public List<ExtensionsList> delExtFile(String path, String title) {
        File file = new File(path);
        List<ExtensionsList> extFileList = new ArrayList<>();
        if (file.exists()) {
            file.delete();
            path = path.substring(0, path.lastIndexOf(File.separator));
            extFileList = ExtensionListUtil.loadExtFileList(path, ExtensionListUtil.getExtensionsList(title));
        }
        return extFileList;
    }

    @ResponseBody
    @PostMapping("/copy/extFile")
    public void copyExtFile(String[] paths) {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        Transferable contents = new Transferable() {
            DataFlavor[] dataFlavors = new DataFlavor[] { DataFlavor.javaFileListFlavor };

            @Override
            public Object getTransferData(DataFlavor flavor)
                    throws UnsupportedFlavorException, IOException {
                return Arrays.stream(paths).map(x -> new File(x)).collect(Collectors.toList());
            }

            @Override
            public DataFlavor[] getTransferDataFlavors() {
                return dataFlavors;
            }

            @Override
            public boolean isDataFlavorSupported(DataFlavor flavor) {
                for (int i = 0; i < dataFlavors.length; i++) {
                    if (dataFlavors[i].equals(flavor)) {
                        return true;
                    }
                }
                return false;
            }
        };
        clipboard.setContents(contents, null);
    }

    @ResponseBody
    @PostMapping("/add/extFile")
    public List<ExtensionsList> addExtFile(@RequestParam(name = "file", required = false) MultipartFile[] files, String path, String title) {
        for (MultipartFile file : files) {
            if (file != null && !file.isEmpty()) {
                String uploadFileName = file.getOriginalFilename();
                if (uploadFileName.contains(".ext")) {
                    path += Util.replaceFileSeparor("/WEB-INF/extensions/") + File.separator + uploadFileName;
                    File dest = new File(path);
                    try {
                        if (!dest.exists()) {
                            file.transferTo(dest);
                        }
                    } catch (IOException e) {
                        System.err.println("上传扩展包失败");
                    }
                }
            }
        }
        if (path.contains("."))
            path = path.substring(0, path.lastIndexOf(File.separator));
        return ExtensionListUtil.loadExtFileList(path, ExtensionListUtil.getExtensionsList(title));
    }

    @ResponseBody
    @PostMapping("/ext/fresh")
    public List<ExtensionsList> refreshExtData(String path, String title) {
        path += Util.replaceFileSeparor("/WEB-INF/extensions");
        return ExtensionListUtil.loadExtFileList(path, ExtensionListUtil.getExtensionsList(title));
    }


    @ResponseBody
    @GetMapping("/openDebug")
    public DataBean<Boolean> openDebug(String title) throws DocumentException {
        String path = ExtensionListUtil.listPath.get(title);
        path += Util.replaceFileSeparor("/WEB-INF/web.xml");
        File file = new File(path);
        if (!file.exists()) {
            return DataBean.fail("web.xml不存在").setData(false);
        }
        Document document = new SAXReader().read(new File(path));
        Element rootElement = document.getRootElement();
        List<Element> beans = rootElement.elements("context-param");
        boolean haveDevEnv = false;
        for (Element bean : beans) {
            String text = bean.element("param-name").getText();
            if ("DevEnv".equals(text)) {
                Element valueElement = bean.element("param-value");
                String value = valueElement.getText();
                if (!"true".equals(value)) {
                    valueElement.setText("true");
                }
                haveDevEnv = true;
            }
        }
        if (!haveDevEnv) {
            Element element = rootElement.addElement("context-param");
            Element param = element.addElement("param-name");
            param.setText("DevEnv");
            Element value = element.addElement("param-value");
            value.setText("true");
        }
        boolean do_JsminBool = false;
        List<Element> servlets = rootElement.elements("servlet");
        for (Element servlet : servlets) {
            String servletName = servlet.element("servlet-name").getText();
            if ("GbkJsp".equals(servletName)) {
                List<Element> params = servlet.elements("init-param");
                for (Element param : params) {
                    String text = param.element("param-name").getText();
                    Element valueElement = param.element("param-value");
                    String value = valueElement.getText();
                    if ("DO-JSMIN".equals(text) && "false".equals(value)) {
                        do_JsminBool = true;
                    } else {
                        valueElement.setText("false");
                    }
                }
            }
        }
        XMLWriter xmlWriter = null;

        OutputFormat format = OutputFormat.createPrettyPrint(); //设置XML文档输出格式
        format.setIndent(true); //设置是否缩进
        format.setIndent("    "); //以空格方式实现缩进
        format.setNewlines(true); //设置是否换行

        try{
            xmlWriter = new XMLWriter(new FileOutputStream(file), format);
            xmlWriter.write(document);
        } catch(Exception e) {
        } finally {
            if(xmlWriter!=null) {
                try {
                    xmlWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return DataBean.success().setDesc("已开启debug").setData(true);
    }

    @ResponseBody
    @GetMapping("/isDebug")
    public DataBean<Boolean> isDebug(String title) throws DocumentException {
        String path = ExtensionListUtil.listPath.get(title);
        path += Util.replaceFileSeparor("/WEB-INF/web.xml");
        File file = new File(path);
        if (!file.exists()) {
            return DataBean.fail("web.xml不存在").setData(false);
        }
        Document document = new SAXReader().read(new File(path));
        Element rootElement = document.getRootElement();
        List<Element> beans = rootElement.elements("context-param");
        boolean haveDevEnv = false;
        for (Element bean : beans) {
            String text = bean.element("param-name").getText();
            if ("DevEnv".equals(text)) {
                String value = bean.element("param-value").getText();
                if ("true".equals(value)) {
                    haveDevEnv = true;
                }
            }
        }
        if (!haveDevEnv) {
            return DataBean.fail("DevEnv参数不存在或为false").setData(false);
        }
        boolean do_JsminBool = false;
        List<Element> servlets = rootElement.elements("servlet");
        for (Element servlet : servlets) {
            String servletName = servlet.element("servlet-name").getText();
            if ("GbkJsp".equals(servletName)) {
                List<Element> params = servlet.elements("init-param");
                for (Element param : params) {
                    String text = param.element("param-name").getText();
                    String value = param.element("param-value").getText();
                    if ("DO-JSMIN".equals(text) && "false".equals(value)) {
                        do_JsminBool = true;
                    }
                }
            }
        }
        if (!do_JsminBool) {
            return DataBean.fail("DO-JSMIN值为true,debug时应为false").setData(false);
        }
        return DataBean.success().setDesc("已开启debug").setData(true);
    }
}
